package com.shop.cloud.common.data.tenant;

import cn.hutool.core.util.StrUtil;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.security.entity.BaseUser;
import com.shop.cloud.upms.common.dto.UserInfo;
import com.shop.cloud.upms.common.feign.FeignUserService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import jakarta.servlet.http.HttpServletRequest;

import java.util.List;
import java.util.Map;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;

/**
 * @author
 */
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@AllArgsConstructor
public class TenantContextHolderFilter extends GenericFilterBean {

	private final RedisTemplate redisTemplate;
	private final FeignUserService feignUserService;

	@Override
	@SneakyThrows
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		//需要token验权的请求，header中有token，通过token找租户ID
		String authorization = request.getHeader(CommonConstants.AUTHORIZATION);
		if(StrUtil.isNotBlank(authorization) && authorization.contains(OAuth2AccessToken.TokenType.BEARER.getValue())){
			String tokenValue = authorization.replace(OAuth2AccessToken.TokenType.BEARER.getValue(), StrUtil.EMPTY).trim();
			String key = StrUtil.concat(false,CacheConstants.OAUTH_CLIENT_CACHE,"::",tokenValue,":*");
			Object[] keys = redisTemplate.keys(key).toArray();
			if(keys.length > 0){
				key = (String) keys[0];
				OAuth2Authorization oAuth2Authorization = (OAuth2Authorization) redisTemplate.opsForValue().get(key);
				if(oAuth2Authorization != null){
					Map<String, Object> additionalInformation =  oAuth2Authorization.getAttributes();
					UsernamePasswordAuthenticationToken principal = (UsernamePasswordAuthenticationToken)additionalInformation.get("java.security.Principal");
					if(principal != null){
						BaseUser baseUser = (BaseUser)principal.getPrincipal();
						String tenantId = baseUser.getTenantId();
						String switchTenantId = request.getHeader(SecurityConstants.SWITCH_TENANT_ID);
						if(StrUtil.isNotEmpty(switchTenantId)
								&& StrUtil.equals(CommonConstants.USER_TYPE_S, StrUtil.toString(baseUser.getType()))
								&& StrUtil.equals(CommonConstants.SYSTEM_TENANT_ID, tenantId)){
							String userName = baseUser.getUsername();
							List<String> listTenantIds;
							if(baseUser != null){
								listTenantIds = baseUser.getTenantIds();
							}else{
								UserInfo userInfo = feignUserService.info(userName, SecurityConstants.FROM_IN).getData();
								listTenantIds = userInfo.getSysUser().getTenantIds();
							}
							if(listTenantIds.contains(switchTenantId)){
								//系统管理员类型用户且该切换的租户ID已和此用户绑定，则设置成Header中指定的租户ID
								tenantId = switchTenantId;
							}
						}
						if (StrUtil.isNotBlank(tenantId)) {
							TenantContextHolder.setTenantId(tenantId);
						}
					}
				}
			}
		}else{
			//不需要token验权的请求，header中无token，用header中的租户ID
			String tenantId = request.getHeader(CommonConstants.TENANT_ID);
			if (StrUtil.isNotBlank(tenantId)) {
				TenantContextHolder.setTenantId(tenantId);
			}
		}

		filterChain.doFilter(request, response);
		TenantContextHolder.clear();
	}
}
